/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _SCSI_CMD_CACHE_
#define _SCSI_CMD_CACHE_

#ifdef CONFIG_EULEROS_SCSI_CMD_CACHE

#include <scsi/scsi_device.h>

struct scsi_mgmt_template {
	int (*cmd_cache_get)(struct scsi_device *sdev, const unsigned char *scsi_cmd, int cmd_len,
						void *buffer, unsigned int buff_len);
	int (*cmd_cache_set)(struct scsi_device *sdev, const unsigned char *scsi_cmd, int cmd_len,
						void *buffer, unsigned int buff_len);
	int (*cmd_cache_remove)(struct scsi_device *sdev);
};

extern int scsi_execute_mgmt_cmd(struct scsi_device *sdev, const unsigned char *scsi_cmd,
								int cmd_len, void *buffer, unsigned int buff_len);
extern int scsi_cache_mgmt_cmd(struct scsi_device *sdev, const unsigned char *scsi_cmd,
								int cmd_len, void *buffer, unsigned int buff_len);
extern int scsi_delete_mgmt_cmd(struct scsi_device *sdev);

extern int scsi_mgmt_handler_register(unsigned int host_no, struct scsi_mgmt_template *template);
extern void scsi_mgmt_handler_unregister(unsigned int host_no);

static inline int scsi_execute_cached_cmd(struct scsi_device *sdev,
	const unsigned char *cmd, int data_direction, void *buffer,
	unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout,
	int retries, int *resid)
{
	int result;
	int cmd_len = COMMAND_SIZE(cmd[0]);

	result = scsi_execute_mgmt_cmd(sdev, cmd, cmd_len, buffer, bufflen);
	if (result) {
		result = scsi_execute_req(sdev, cmd, data_direction, buffer, bufflen,
						sshdr, timeout, retries, resid);
		if (!result)
			scsi_cache_mgmt_cmd(sdev, cmd, cmd_len, buffer, bufflen);
	}

	return result;
}

#define scsi_execute_req_ex	scsi_execute_cached_cmd

#else /* !CONFIG_EULEROS_SCSI_CMD_CACHE */

#define scsi_delete_mgmt_cmd(sdev)	do { } while (0)
#define scsi_execute_req_ex	scsi_execute_req

#endif /* CONFIG_EULEROS_SCSI_CMD_CACHE */

#endif

